﻿<UserControl 
    x:Class="Imagin.Controls.Extended.PropertyGrid"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:l="http://wpflocalizeextension.codeplex.com"
    xmlns:local="clr-namespace:Imagin.Controls.Extended"
    xmlns:Common="http://imagin.tech/imagin/common"
    xmlns:Controls.Common="http://imagin.tech/imagin/controls/common"
    xmlns:Controls.Extended.Converters="clr-namespace:Imagin.Controls.Extended.Converters"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    xmlns:System.2="clr-namespace:System;assembly=System"
    xmlns:System.Collections="clr-namespace:System.Collections;assembly=mscorlib"
    xmlns:System.ComponentModel="clr-namespace:System.ComponentModel;assembly=System"
    xmlns:System.Net="clr-namespace:System.Net;assembly=System"
    xmlns:System.Windows="clr-namespace:System.Windows;assembly=WindowsBase"
    xmlns:System.Windows.Media="clr-namespace:System.Windows.Media;assembly=PresentationCore"
    x:Name="PART_PropertyGrid">
    <UserControl.Resources>
        <Common:BindingProxy x:Key="BindingProxy"  Data="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:PropertyGrid}}}"/>

        <!-- ....................................................... Converters -->

        <Common:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
        <Common:ObjectToTypeConverter x:Key="ObjectToTypeConverter"/>
        <Common:NullToBooleanConverter x:Key="NullToBooleanConverter"/>
        <Common:InverseBooleanConverter x:Key="InverseBooleanConverter"/>
        <Common:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
        <Common:StringToCamelCaseConverter x:Key="StringToCamelCaseConverter"/>
        <Common:EnumToCamelCaseConverter x:Key="EnumToCamelCaseConverter"/>
        <Common:EnumToCollectionConverter x:Key="EnumToCollectionConverter"/>
        <Common:FileSizeMultiValueConverter x:Key="FileSizeMultiValueConverter"/>
        <Common:StringToVisibilityConverter x:Key="StringToVisibilityConverter"/>
        <Common:SolidColorBrushToHexConverter x:Key="SolidColorBrushToHexConverter"/>
        <Common:StartsWithToVisibilityMultiValueConverter x:Key="StartsWithToVisibilityMultiValueConverter"/>

        <Controls.Extended.Converters:FeaturedPropertyVisibilityConverter x:Key="FeaturedPropertyVisibilityConverter"/>

        <!-- ....................................................... Styles -->

        <Style 
            x:Key="Style.Cell"
            TargetType="{x:Type DataGridCell}" 
            BasedOn="{StaticResource {x:Type DataGridCell}}">
            <Setter Property="Padding" Value="10,1"/>
        </Style>

        <Style x:Key="Style.DataGrid.Row" TargetType="{x:Type DataGridRow}">
            <Setter Property="TextElement.Foreground" Value="{Binding Foreground, ElementName=PART_PropertyGrid}" />
            <Setter Property="Visibility">
                <Setter.Value>
                    <MultiBinding Converter="{StaticResource StartsWithToVisibilityMultiValueConverter}" BindingGroupName="{x:Null}">
                        <Binding Path="Name" Converter="{StaticResource StringToCamelCaseConverter}"/>
                        <Binding Path="SearchQuery" RelativeSource="{RelativeSource AncestorType={x:Type local:PropertyGrid}}"/>
                    </MultiBinding>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsSelected" Value="False" />
                        <Condition Property="IsMouseOver" Value="True" />
                    </MultiTrigger.Conditions>
                    <Setter Property="Background" Value="Transparent"/>
                </MultiTrigger>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsSelected" Value="True" />
                        <Condition Property="IsMouseOver" Value="True" />
                    </MultiTrigger.Conditions>
                    <Setter Property="Background" Value="Transparent"/>
                </MultiTrigger>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsSelected" Value="True" />
                        <Condition Property="Selector.IsSelectionActive" Value="False" />
                        <Condition Property="IsMouseOver" Value="False" />
                    </MultiTrigger.Conditions>
                    <Setter Property="Background" Value="Transparent"/>
                </MultiTrigger>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsSelected" Value="True" />
                        <Condition Property="Selector.IsSelectionActive" Value="True" />
                        <Condition Property="IsMouseOver" Value="False" />
                    </MultiTrigger.Conditions>
                    <Setter Property="Background" Value="Transparent"/>
                </MultiTrigger>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsSelected" Value="False" />
                        <Condition Property="ItemsControl.AlternationIndex" Value="0" />
                        <Condition Property="IsMouseOver" Value="False" />
                    </MultiTrigger.Conditions>
                    <Setter Property="Background" Value="Transparent"/>
                </MultiTrigger>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsSelected" Value="False" />
                        <Condition Property="ItemsControl.AlternationIndex" Value="1" />
                        <Condition Property="IsMouseOver" Value="False" />
                    </MultiTrigger.Conditions>
                    <Setter Property="Background" Value="Transparent"/>
                </MultiTrigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="Style.DataGrid.GroupHeader" TargetType="{x:Type GroupItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type GroupItem}">
                        <Expander Header="{Binding Name}" IsExpanded="{Binding CollapseGroups, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type local:PropertyGrid}}, Converter={StaticResource InverseBooleanConverter}}">
                            <ItemsPresenter/>
                        </Expander>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- ....................................................... Templates -->
        
        <ResourceDictionary x:Key="Resources.Templates">
            <DataTemplate x:Key="{x:Type System:Boolean}">
                <CheckBox 
                    HorizontalAlignment="Left" 
                    IsChecked="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                    IsEnabled="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                    Margin="0,5"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:Byte}">
                <Controls.Common:ByteUpDown 
                    HorizontalAlignment="Stretch"
                    IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                    CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                    Maximum="{Binding Maximum}"
                    Minimum="{Binding Minimum}"
                    StringFormat="{Binding StringFormat}"
                    Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System.Collections:IList}">
                <Grid Margin="0,7">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock 
                        Text="{l:LocText Prefix=(, Key=Collection, Suffix=)}"/>
                    <Controls.Common:MaskedButton
                        Grid.Column="1"
                        Command="{x:Static local:PropertyGrid.EditCollectionCommand}"
                        CommandParameter="{Binding Value, Mode=OneWay}"
                        Padding="7,0,0,0"
                        Source="pack://application:,,,/Imagin.Controls.Extended;component/Images/Pencil.png"/>
                </Grid>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:DateTime}">
                <Controls.Common:DateTimeUpDown 
                    HorizontalAlignment="Stretch"
                    IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                    CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                    Maximum="{Binding Maximum}"
                    Minimum="{Binding Minimum}"
                    StringFormat="{Binding StringFormat}"
                    Value="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:Decimal}">
                <Controls.Common:DecimalUpDown 
                    HorizontalAlignment="Stretch"
                    IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                    CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                    Maximum="{Binding Maximum}"
                    Minimum="{Binding Minimum}"
                    StringFormat="{Binding StringFormat}"
                    Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:Double}">
                <Controls.Common:DoubleUpDown 
                    HorizontalAlignment="Stretch"
                    IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                    CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                    Maximum="{Binding Maximum}"
                    Minimum="{Binding Minimum}"
                    StringFormat="{Binding StringFormat}"
                    Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:Enum}">
                <ComboBox
                    IsEnabled="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                    ItemsSource="{Binding Value, Mode=OneTime, Converter={StaticResource EnumToCollectionConverter}}" 
                    SelectedValue="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                    VirtualizingPanel.IsVirtualizing="True" 
                    VirtualizingPanel.VirtualizationMode="Recycling">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Mode=OneWay, Converter={StaticResource EnumToCamelCaseConverter}}"/>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System.Windows.Media:LinearGradientBrush}">
                <local:GradientChip 
                    Height="25"
                    Value="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                    Width="Auto"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:Guid}">
                <Controls.Common:RegexBox 
                    HorizontalAlignment="Stretch"
                    IsReadOnly="{Binding IsReadOnly, Mode=OneWay}" 
                    Pattern="^([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$"
                    Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:Int16}">
                <Controls.Common:ShortUpDown 
                    HorizontalAlignment="Stretch"
                    IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                    CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                    Maximum="{Binding Maximum}"
                    Minimum="{Binding Minimum}"
                    StringFormat="{Binding StringFormat}"
                    Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:Int32}">
                <Controls.Common:IntUpDown 
                    HorizontalAlignment="Stretch"
                    IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                    CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                    Maximum="{Binding Maximum}"
                    Minimum="{Binding Minimum}"
                    StringFormat="{Binding StringFormat}"
                    Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:Int64}">
                <ContentControl x:Name="PART_Content">
                    <Controls.Common:LongUpDown 
                        HorizontalAlignment="Stretch"
                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                        CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                        Maximum="{Binding Maximum}"
                        Minimum="{Binding Minimum}"
                        StringFormat="{Binding StringFormat}"
                        Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                </ContentControl>
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding Tag}" Value="FileSize">
                        <Setter TargetName="PART_Content" Property="Content">
                            <Setter.Value>
                                <TextBlock Margin="0,10">
                                    <TextBlock.Text>
                                        <MultiBinding Converter="{StaticResource FileSizeMultiValueConverter}">
                                            <Binding Path="Value" Mode="OneWay"/>
                                            <Binding Path="Data.FileSizeFormat" Source="{StaticResource BindingProxy}"/>
                                        </MultiBinding>
                                    </TextBlock.Text>
                                </TextBlock>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System.Net:NetworkCredential}">
                <StackPanel IsEnabled="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}">
                    <Controls.Common:TextBoxExt
                        Margin="0,0,0,5"
                        Placeholder="{l:Loc Username}"
                        Text="{Binding Value.UserName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                    <Controls.Common:PasswordBox
                        Placeholder="{l:Loc Password}"
                        Text="{Binding Value.Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                </StackPanel>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System.Windows:Point}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    
                    <Controls.Common:DoubleUpDown 
                        CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                        Margin="0,0,5,0"
                        Minimum="{Binding Minimum.X}"
                        StringFormat="{Binding StringFormat}"
                        Text="{Binding Variant.X, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        ToolTip="{l:Loc X}"/>
                    <Controls.Common:DoubleUpDown 
                        Grid.Column="1"
                        Grid.Row="1"
                        CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                        Minimum="{Binding Minimum.Y}"
                        StringFormat="{Binding StringFormat}"
                        Text="{Binding Variant.Y, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        ToolTip="{l:Loc Y}"/>
                </Grid>
            </DataTemplate>
            
            <!-- Nested -->
            <DataTemplate x:Key="{x:Type System:Object}">
                <ContentControl
                    Content="{Binding Mode=OneWay}"
                    ContentStringFormat="{Binding Data.NestedPropertyStringFormat, Source={StaticResource BindingProxy}}"
                    ContentTemplate="{Binding Data.NestedPropertyTemplate, Source={StaticResource BindingProxy}}"
                    ContentTemplateSelector="{Binding Data.NestedPropertyTemplateSelector, Source={StaticResource BindingProxy}}"/>
            </DataTemplate>
            
            <DataTemplate x:Key="{x:Type System.Windows:Size}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>

                    <Controls.Common:DoubleUpDown
                        x:Name="PART_Width"
                        CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                        Minimum="0"
                        StringFormat="{Binding StringFormat}"
                        Text="{Binding Variant.Width, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        ToolTip="{l:Loc Width}"/>
                    <Controls.Common:MaskedToggleButton
                        Grid.Column="1"
                        CheckedToolTip="{l:Loc Unbind}"
                        IsChecked="{Binding Tag, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        Padding="7,0"
                        Source="pack://application:,,,/Imagin.Controls.Extended;component/Images/LinkHorizontal.png"
                        UncheckedToolTip="{l:Loc Bind}"/>
                    <Controls.Common:DoubleUpDown
                        Grid.Column="2"
                        x:Name="PART_Height"
                        CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                        Minimum="0"
                        StringFormat="{Binding StringFormat}"
                        Text="{Binding Variant.Height, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        ToolTip="{l:Loc Height}"/>
                </Grid>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System.Windows.Media:SolidColorBrush}">
                <Grid IsEnabled="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <local:ColorChip
                        Value="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                        Width="25" 
                        Height="25" 
                        Margin="0,0,5,0"/>
                    <Controls.Common:AlphaNumericBox
                        Grid.Column="1"  
                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                        MaxLength="8"
                        Text="{Binding Value, Mode=TwoWay, Converter={StaticResource SolidColorBrushToHexConverter}, UpdateSourceTrigger=LostFocus}"/>
                </Grid>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:String}">
                <ContentControl 
                    x:Name="PART_Content"
                    Content="{Binding Mode=OneWay}">
                    <ContentControl.ContentTemplate>
                        <DataTemplate>
                            <Controls.Common:TextBoxExt 
                                HorizontalAlignment="Stretch"
                                IsReadOnly="{Binding IsReadOnly, Mode=OneWay}" 
                                Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                        </DataTemplate>
                    </ContentControl.ContentTemplate>
                </ContentControl>
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding Tag, UpdateSourceTrigger=PropertyChanged}" Value="FilePath">
                        <Setter TargetName="PART_Content" Property="ContentTemplate">
                            <Setter.Value>
                                <DataTemplate>
                                    <Controls.Common:FileBox  
                                        BrowseMode="OpenFile"
                                        CanBrowse="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                                        HorizontalAlignment="Stretch"
                                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                                        Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Tag, UpdateSourceTrigger=PropertyChanged}" Value="FolderPath">
                        <Setter TargetName="PART_Content" Property="ContentTemplate">
                            <Setter.Value>
                                <DataTemplate>
                                    <Controls.Common:FileBox  
                                        BrowseMode="OpenFolder"
                                        CanBrowse="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                                        HorizontalAlignment="Stretch"
                                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                                        Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Tag, UpdateSourceTrigger=PropertyChanged}" Value="Multiline">
                        <Setter TargetName="PART_Content" Property="ContentTemplate">
                            <Setter.Value>
                                <DataTemplate>
                                    <Controls.Common:TextBoxExt 
                                        AcceptsReturn="True"
                                        Height="Auto"
                                        HorizontalAlignment="Stretch"
                                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}" 
                                        Padding="3"
                                        Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                        TextBlock.LineStackingStrategy="BlockLineHeight"
                                        TextBlock.LineHeight="15"
                                        VerticalContentAlignment="Top"
                                        TextWrapping="Wrap"/>
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Tag, UpdateSourceTrigger=PropertyChanged}" Value="Password">
                        <Setter TargetName="PART_Content" Property="ContentTemplate">
                            <Setter.Value>
                                <DataTemplate>
                                    <Controls.Common:PasswordBox 
                                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                                        Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                        HorizontalAlignment="Stretch"/>
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Tag, UpdateSourceTrigger=PropertyChanged}" Value="Tokens">
                        <Setter TargetName="PART_Content" Property="ContentTemplate">
                            <Setter.Value>
                                <DataTemplate>
                                    <Controls.Common:TokenView 
                                        IsReadOnly="{Binding IsReadOnly, Mode=OneWay}"
                                        HorizontalAlignment="Stretch"
                                        TokensSource="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System.2:Uri}">
                <Controls.Common:RegexBox 
                    HorizontalAlignment="Stretch"
                    IsReadOnly="{Binding IsReadOnly, Mode=OneWay}" 
                    Pattern="^(http|https|ftp|)\://|[a-zA-Z0-9\-\.]+\.[a-zA-Z](:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\'/\\\+&amp;%\$#\=~])*[^\.\,\)\(\s]$"
                    Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
            <DataTemplate x:Key="{x:Type System:Version}">
                <Grid
                    IsEnabled="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                    Controls.Common:PanelExtensions.Spacing="0,0,5,0"
                    Controls.Common:PanelExtensions.TrimLast="True">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Controls.Common:IntUpDown
                        CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                        Minimum="{x:Static Common:Release.MinValue}"
                        Text="{Binding Variant.Major, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        ToolTip="{l:Loc Major}"/>
                    <Controls.Common:IntUpDown
                        Grid.Column="1"
                        CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                        Minimum="{x:Static Common:Release.MinValue}"
                        Text="{Binding Variant.Minor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        ToolTip="{l:Loc Minor}"/>
                    <Controls.Common:IntUpDown
                        Grid.Column="2"
                        CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                        Minimum="{x:Static Common:Release.MinValue}"
                        Text="{Binding Variant.Build, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        ToolTip="{l:Loc Build}"/>
                    <Controls.Common:IntUpDown
                        Grid.Column="3"
                        CanUpDown="{Binding IsReadOnly, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"
                        Minimum="{x:Static Common:Release.MinValue}"
                        Text="{Binding Variant.Revision, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        ToolTip="{l:Loc Revision}"/>
                </Grid>
            </DataTemplate>
        </ResourceDictionary>

        <DataTemplate x:Key="PropertyModelTemplate">
            <ContentControl Content="{Binding}">
                <ContentControl.ContentTemplateSelector>
                    <local:PropertyTemplateSelector Resources="{StaticResource Resources.Templates}"/>
                </ContentControl.ContentTemplateSelector>
            </ContentControl>
        </DataTemplate>
    </UserControl.Resources>
    <Grid DataContext="{Binding ElementName=PART_PropertyGrid}">
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- ....................................................... Header -->
        <Grid 
            IsEnabled="{Binding SelectedObject, Converter={StaticResource NullToBooleanConverter}}"
            Controls.Common:PanelExtensions.Spacing="0,0,10,0"
            Visibility="{Binding ShowHeader, Converter={StaticResource BooleanToVisibilityConverter}}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <!-- Custom Buttons -->
            <ItemsControl
                ItemsSource="{Binding Buttons, Mode=OneWay}"
                VerticalAlignment="Center">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding Mode=OneWay}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

            <!-- Default Buttons -->
            
            <Controls.Common:MaskedButton
                Grid.Column="1"
                Command="{Binding RewindNestCommand}"
                Source="pack://application:,,,/Imagin.Controls.Extended;component/Images/ArrowLeftRound.png"
                ToolTip="{l:Loc Back}"
                VerticalAlignment="Center"
                Visibility="{Binding IsEnabled, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay, RelativeSource={RelativeSource Self}, UpdateSourceTrigger=PropertyChanged}"/>
            <Controls.Common:MaskedToggleButton
                Grid.Column="2"
                Source="pack://application:,,,/Imagin.Controls.Extended;component/Images/Category.png"
                IsChecked="{Binding ShowCategories}"
                CheckedToolTip="Showing Categories"
                UncheckedToolTip="Show Categories"
                VerticalAlignment="Center"/>
            <Controls.Common:MaskedDropDownButton
                Grid.Column="3"
                Source="pack://application:,,,/Imagin.Controls.Extended;component/Images/Sort.png"
                ToolTip="{l:Loc SortDirection}"
                VerticalAlignment="Center">
                <Controls.Common:MaskedDropDownButton.DropDown>
                    <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
                        <MenuItem 
                            Header="{l:Loc Name}" 
                            IsCheckable="True" 
                            IsChecked="{Binding SortByName, UpdateSourceTrigger=PropertyChanged}" 
                            Controls.Common:MenuItemExtensions.GroupName="SortName"
                            StaysOpenOnClick="True"/>
                        <MenuItem 
                            Header="{l:Loc Type}" 
                            IsCheckable="True" 
                            IsChecked="{Binding SortByType, UpdateSourceTrigger=PropertyChanged}"
                            Controls.Common:MenuItemExtensions.GroupName="SortName"
                            StaysOpenOnClick="True"/>
                        <Separator/>
                        <MenuItem 
                            Header="{l:Loc Ascending}" 
                            IsCheckable="True" 
                            IsChecked="{Binding IsSortAscending, UpdateSourceTrigger=PropertyChanged}" 
                            Controls.Common:MenuItemExtensions.GroupName="SortDirection"
                            StaysOpenOnClick="True"/>
                        <MenuItem 
                            Header="{l:Loc Descending}"
                            IsCheckable="True" 
                            IsChecked="{Binding IsSortDescending, UpdateSourceTrigger=PropertyChanged}" 
                            Controls.Common:MenuItemExtensions.GroupName="SortDirection"
                            StaysOpenOnClick="True"/>
                    </ContextMenu>
                </Controls.Common:MaskedDropDownButton.DropDown>
            </Controls.Common:MaskedDropDownButton>
            
            <!-- Search -->
            <Controls.Common:MaskedImage
                Grid.Column="4"
                Source="pack://application:,,,/Imagin.Controls.Extended;component/Images/Search.png"/>
            <Controls.Common:TextBoxExt
                Grid.Column="5"
                CanUserClear="True"
                Padding="0"
                Placeholder="{l:Loc Search}"
                Text="{Binding SearchQuery, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                ToolTip="{l:Loc Search}"
                Background="Transparent"
                BorderThickness="0"/>

            <!-- Options -->
            <Controls.Common:MaskedDropDownButton
                Grid.Column="6"
                Source="pack://application:,,,/Imagin.Controls.Extended;component/Images/ArrowDown.png"
                ToolTip="{l:Loc Options}">
                <Controls.Common:MaskedDropDownButton.DropDown>
                    <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
                        <MenuItem 
                            Header="{l:Loc CollapseGroups}" 
                            IsCheckable="True"
                            IsChecked="{Binding CollapseGroups}"
                            StaysOpenOnClick="True"/>
                        <Separator/>
                        <MenuItem 
                            Header="{l:Loc Reset}" 
                            Command="{x:Static local:PropertyGrid.ResetCommand}"/>
                    </ContextMenu>
                </Controls.Common:MaskedDropDownButton.DropDown>
            </Controls.Common:MaskedDropDownButton>
        </Grid>

        <!-- ....................................................... Body -->
        <Border
            Grid.Row="1"
            Background="{Binding GridBackground}"
            BorderBrush="{Binding GridBorderBrush}"
            BorderThickness="{Binding GridBorderThickness}">
            <Grid>
                <!-- Loader -->
                <ContentControl
                    ContentTemplate="{Binding LoaderTemplate}"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                
                <Grid Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Inverted}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    
                    <!-- Type -->
                    <ContentControl
                        Content="{Binding SelectedObject, Mode=OneWay}"
                        ContentStringFormat="{Binding TypeStringFormat}"
                        ContentTemplate="{Binding TypeTemplate}"
                        ContentTemplateSelector="{Binding TypeTemplateSelector}"
                        Visibility="{Binding ShowType, Converter={StaticResource BooleanToVisibilityConverter}}"/>

                    <!-- Featured -->
                    <Grid 
                        Grid.Row="1"
                        Margin="10,5,5,10">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.Visibility>
                            <MultiBinding Converter="{StaticResource FeaturedPropertyVisibilityConverter}">
                                <Binding Path="ShowFeatured"/>
                                <Binding Path="Properties.Featured"/>
                            </MultiBinding>
                        </Grid.Visibility>
                        
                        <Label 
                            Content="{Binding Properties.Featured.Name, Mode=OneWay}" 
                            Margin="0,0,10,0" 
                            VerticalAlignment="Center"/>
                        <ContentControl
                            Grid.Column="1"
                            Content="{Binding Properties.Featured, Mode=OneWay}"
                            ContentTemplate="{StaticResource PropertyModelTemplate}"/>
                    </Grid>

                    <!-- DataGrid -->
                    <DataGrid
                        Grid.Row="2"
                        AutoGenerateColumns="False"
                        CanUserAddRows="False"
                        CanUserDeleteRows="False"
                        CellStyle="{StaticResource Style.Cell}"
                        GridLinesVisibility="{Binding GridLinesVisibility}"
                        HeadersVisibility="{Binding HeadersVisibility}"
                        ItemContainerStyle="{StaticResource Style.DataGrid.Row}"
                        ItemsSource="{Binding ListCollectionView, IsAsync=True}"
                        ScrollViewer.HorizontalScrollBarVisibility="Auto"
                        ScrollViewer.VerticalScrollBarVisibility="Auto"
                        SelectedValue="{Binding Properties.ActiveProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        SelectionMode="Single"
                        Style="{Binding GridStyle}">
                        <DataGrid.Columns>
                            <DataGridTemplateColumn
                                Header="Name"
                                SortMemberPath="Name" 
                                Width="{Binding Data.PropertyColumnWidth, Source={StaticResource BindingProxy}}">
                                <DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock 
                                            Text="{Binding Name, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource StringToCamelCaseConverter}}"
                                            TextTrimming="CharacterEllipsis"
                                            ToolTip="{Binding Text, Mode=OneWay, RelativeSource={RelativeSource Self}}"
                                            VerticalAlignment="Center"/>
                                    </DataTemplate>
                                </DataGridTemplateColumn.CellTemplate>
                            </DataGridTemplateColumn>
                            <DataGridTemplateColumn 
                                CellTemplate="{StaticResource PropertyModelTemplate}" 
                                Header="Value" 
                                Width="{Binding Data.ValueColumnWidth, Source={StaticResource BindingProxy}}"/>
                        </DataGrid.Columns>
                        <DataGrid.GroupStyle>
                            <GroupStyle ContainerStyle="{StaticResource Style.DataGrid.GroupHeader}">
                                <GroupStyle.Panel>
                                    <ItemsPanelTemplate>
                                        <DataGridRowsPresenter/>
                                    </ItemsPanelTemplate>
                                </GroupStyle.Panel>
                            </GroupStyle>
                        </DataGrid.GroupStyle>
                    </DataGrid>
                </Grid>
            </Grid>
        </Border>
        
        <!-- ....................................................... Footer -->
        <GridSplitter
            Grid.Row="2"
            ResizeDirection="Rows"
            Style="{Binding SplitterStyle}"
            Visibility="{Binding CanResizeDescription, Converter={StaticResource BooleanToVisibilityConverter}}"/>
        <ContentControl 
            Grid.Row="3"
            Content="{Binding Properties.ActiveProperty}"
            ContentStringFormat="{Binding DescriptionStringFormat}"
            ContentTemplate="{Binding DescriptionTemplate}"
            ContentTemplateSelector="{Binding DescriptionTemplateSelector}"
            MinHeight="25"
            Visibility="{Binding DescriptionVisibility}"/>
    </Grid>
</UserControl>
